Very brief and cryptic notes about the source release of OSLib
==== ===== === ======= ===== ===== === ====== ======= == =====

   It's 14Mb built. The part you use (headers + library) is 3Mb big.

   This is 5.3. See ChangeLog for changes since 5.2.

   The most important coding point to emphasise is that *all* errors are
detected and reported, no matter how deeply nested we may be into the call
stack or however small the function in progress. This is done by keeping to
a strict discipline (when I can be bothered :-)

   Every function that everyone has ever written can return an error.
Normally in RISC O S code this is done by returning an |os_error *|. In
UNIX-style code, it is done by returning -1 and setting |errno|. Whatever
the mechanism is, it *must* be checked when calling the function. Every
function called *must* then have its error return checked. If there was an
error, a |goto finish;| is executed immediately. (The only thing that can be
done before "go to finish" is to assign the current function's error
indicator.) At |finish:|, any local resources that may have been claimed (in
C, chiefly malloced memory and file handlers, but under RISC O S also
windows, fonts, vectors, etc) are released. The current function then
returns the error back to its own caller.

   In this way, when any function returns an error, the whole of the call
stack is unwound to the top level where it can be handled cleanly. This is a
just a low-level way of emulating C++-style exceptions.

   The other important point is regression testing. When a change is
made, everything is differed with the previous version to make sure that
nothing has changed for the worse. For the objasm files, I've provided s;0
directories, but it should be done for headers too: that's easy because they
are textual anyway, and you already have copies. The objasm diff checks that
the *code* is the same. (The objasm files aren't used for anything else, but
the code that writes them is the same as the code that writes the tiny files
that make up the library as a whole, so it's important.)

   This is your guarantee that everything you do will work.

   Installation is roughly as follows: run SetVars; open DefMod; run !Make
(twice) (you need yacc (or Bison) for this); copy the DefMod absolute into
the OSLib directory, or into your path; run !Make in OSlib.

   The comments in the objasm files "Registers available for scratch use"
was a piece of work-in-progress. The idea was from Mark Wooding, I think: he
suggested that instead of stacking values that must be saved over the SWI,
it would be more efficient to save them in registers that were not otherwise
used. (These are V1--V6 if the SWI will corrupt them, as A P C S demands
they are preserved by a function call, and any registers containing
addresses of output arguments that are needed on entry to the SWI or
corrupted by it.) This is commented out, not finished, and doesn't work.
Feel free to give it a shot.

   DefMod can make SrcEdit help files for either C or assembler---no-one
wants these, though. I also started something to do with Pascal, as well as
a start to native C++ support (so you wouldn't need the |extern "C"|
directives, and potentially allow overloaded functions to call the same
SWI).

   I think that defining NDEBUG would stop lookup.c working. That was
probably a mistake.

   DefMod is a RISC O S programme written in C, and it looks as though it
uses OSLib. If it did, it could never have been written, as it logically
precedes OSLib. So how was this done?

   It uses a hand-crafted set of macros called SWILib. This defines the
functions provided by OSLib as macros expanding to calls to
|_swi(x?)|---but just the SWI's that DefMod uses. (SWILib was the first
version of OSLib. The first version of DefMod generated SWILib-style
headers: macros rather than function declarations.) Do not change this, or
you could potentially end up in a situation where the whole system could not
get off the ground.

   There are sketches or starts or initial hacks at some more swi files in
InProgress.

   I have been asked to explain the way the [UNKNOWN] types work. When a
type (e g, wimp_menu, wimp_window) has a repeating final part, DefMod also
generates some extra macros wimp_MENU (n) and wimp_SIZEOF_MENU (n). You can
use the first to write out data structures in your code. It does show how
flexible the C type system is, if you use it well. Here's a menu definition
I use in another of my proggies ...

      wimp_MENU (2) Main_Menu =
      {
         "PlaceName",
         wimp_COLOUR_BLACK,
         wimp_COLOUR_LIGHT_GREY,
         wimp_COLOUR_BLACK,
         SKIP,
         9*wimp_CHAR_XSIZE,
         wimp_MENU_ITEM_HEIGHT,
         wimp_MENU_ITEM_GAP,
         {
            {
               wimp_MENU_GIVE_WARNING,
               wimp_DEFER_SUB_MENU,
               wimp_ICON_TEXT | wimp_ICON_FILLED |
                     wimp_COLOUR_BLACK << wimp_ICON_FG_COLOUR_SHIFT |
                     wimp_COLOUR_WHITE << wimp_ICON_BG_COLOUR_SHIFT,
               "Info"
            },
            {
               wimp_MENU_LAST,
               wimp_NO_SUB_MENU,
               wimp_ICON_TEXT | wimp_ICON_FILLED |
                     wimp_COLOUR_BLACK << wimp_ICON_FG_COLOUR_SHIFT |
                     wimp_COLOUR_WHITE << wimp_ICON_BG_COLOUR_SHIFT,
               "Quit"
            }
         }
      };

   This is then used in calls like

      wimp_create_menu ((wimp_menu *) &Main_Menu);

---it needs to be cast. If you want to build a structure like this on the
fly, you can write

      wimp_menu *menu = malloc (wimp_SIZEOF_MENU (2));

and use references like

      ... menu->entries [1].data AS indirected_text.text ...

to get at the text of the 1st icon.

   So these macros can let you write some very complicated data structures
right in the code, without needing to read them from a resource file, but
still in a reasonably maintainable way.

   In general, you you must always make sure you know where a module fits in
with other modules. There must be a strict hierarchy, with files only
needing (the NEEDS statement) files in an acyclic fashion. That's not say
things can't be introduced into the middle (JPEG needs OS, but PDriver needs
JPEG, even though JPEG didn't exist till long after PDriver was first
thought of.) DrawFile is another complicated one: does DrawFile need Font
(Draw objects can contain font handles), or does Font need DrawFile (the
Font manager can write font outlines to a Draw group). This is a tie really,
and it's broken in an unpleasant way. It might have been better to invent a
"graphics.h" to be included by both, but that would break the
correspondence between swi files and modules.

   There are lots of cases in RISC O S of extensible interfaces: Wimp
messages can be defined by anyone, for example. It is not good in these
cases to put all of them into a file (swi.Wimp): this would mean that the
file would have to be extended all the time. Instead, the basic interface is
provided in 1 file, and other people can write their own header files. This
is what's done in swi.Gadget. No gadget types are defined there: that's all
done in a distributed way. This is also why the wimp_message struct only has
a few of the defined message data types in its data field. (It has all of
the ones defined as "system" and "Wimp" types.) Ones defined by modules
(e g, message_HELP_REQUEST, printing messages, alarm messages) are defined
by their respective modules. Otherwise, every time a new module added a
message, "wimp.h" would have to be updated. This means that some otherwise
avoidable type casts are needed; oh well.

   DefMod writes HelpData and Index files for use by StrongHelp. These are
all copied into a big archive by the Make process. (This has to be an
archive only because there are lots more than 77 files). Then
Alexander Thoukidides' ConvHelp can turn all of these into a StrongHelp help
file. If you use Zap, you can bind F1 to mje_helpcontext, and then you point
to a SWI name in your code and get help on it in 1 keystroke. This help is
all linked together internally, and in 2 clicks you can get all the valid
values for any constant.

   You need a version of YACC or Bison. The one I used was ported by me from
the Berkeley YACC sources. I could have used Bison, but then OSlib would
have fallen under the G P L. At that time, I wanted to keep the 'swi' files
private, so that there wouldn't be incompatible extensions to widely-used
modules; but I'm convinced now that that isn't a problem. The approach to
the parsing is is unconventional in 2 ways: (1) I didn't use Lex (or Flex):
everything is done by the grammar in defmod.y. This was just so I didn't
have to learn Lex as well as YACC, and to see if it could be done. (2)
String values are not put in a symbol table and carefully managed. Instead,
the grammar passes round whole strings of up to 255 characters on the stack
and copies them every time a character is appended. This is hopelessly slow
and inefficient---but it works, and it's "fast enough". The limit is not
checked in the code, despite what I said above. Sorry.

   CD, CDFS, MIDI seem to need special attention.
